package com.sc.nft.hna.form;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.asymmetric.Sign;
import cn.hutool.crypto.asymmetric.SignAlgorithm;
import com.alibaba.fastjson.JSONObject;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.*;

import com.sc.nft.config.hna.HnaConfig;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.sup.ErrorCode;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.reflections.Reflections;
import org.reflections.util.ConfigurationBuilder;

@Data
@Slf4j
public abstract class BaseTransForm implements Serializable {

  private static final Reflections REFLECTIONS =
      new Reflections(new ConfigurationBuilder().forPackages("com.sc.nft.hna"));
  private static final Set<Class<? extends BaseTransForm>> SUBTYPE_SET =
      REFLECTIONS.getSubTypesOf(BaseTransForm.class);

  public static final String VERSION = "version";
  public static final String TRAN_CODE = "tranCode";
  public static final String MER_ID = "merId";
  public static final String MER_ORDER_ID = "merOrderId";
  public static final String CHARSET = "charset";
  public static final String SIGN_TYPE = "signType";
  public static final String SIGN_VALUE = "signValue";
  public static final String MER_ATTACH = "merAttach";
  public static final String SUBMIT_TIME = "submitTime";
  public static final String MSG_CIPHER_TEXT = "msgCiphertext";
  public static final String RESULT_CODE = "resultCode";
  public static final String ERROR_CODE = "errorCode";
  public static final String ERROR_MSG = "errorMsg";
  private static final long serialVersionUID = 2140963890796928237L;

  // 暂定公共的报文字段
  protected String tranCode;
  protected String version;
  protected String merId;
  protected String merOrderId;
  protected String signType;
  protected String signValue;
  protected String msgCiphertext;
  protected String charset;
  protected String merAttach;
  protected String submitTime;

  // 提交地址
  protected String submitUrl;

  /**
   * 获取公共返回参数<br>
   * Map中的key必须与返回XML文件中的field的name值一致<br>
   * 子类可选择性重写
   */
  @SuppressWarnings("static-access")
  public Map<String, Object> getCommonRespParams() {
    Map<String, Object> commonParams = new HashMap<>();
    commonParams.put(VERSION, version);
    commonParams.put(TRAN_CODE, tranCode);
    commonParams.put(MER_ORDER_ID, merOrderId);
    commonParams.put(MER_ID, merId);
    commonParams.put(MER_ATTACH, merAttach);
    commonParams.put(CHARSET, charset);
    commonParams.put(SIGN_TYPE, signType);
    return commonParams;
  }

  /** 获取共用请求的签名字段 */
  @SuppressWarnings("static-access")
  public Map<String, Object> getCommonReqSignParams() {
    Map<String, Object> commonParams = new HashMap<String, Object>();
    commonParams.put(TRAN_CODE, tranCode);
    commonParams.put(VERSION, version);
    commonParams.put(MER_ID, merId);
    commonParams.put(MER_ATTACH, merAttach);
    commonParams.put(MER_ORDER_ID, merOrderId);
    commonParams.put(SUBMIT_TIME, submitTime);
    commonParams.put(MSG_CIPHER_TEXT, msgCiphertext);
    commonParams.put(SIGN_TYPE, signType);
    return commonParams;
  }

  /** 获取加密json串明文 */
  public abstract String getEncryptJsonStr();

  /** 获取验签字段 */
  public abstract String getVerifyJsonStr();

  /** 获取提交字段 */
  public abstract String getSubmitJsonStr();

  public void initCommonParams(String tranCode, String merId, String merOrderId, String merAttach) {
    version = "1.0";
    this.merId = merId;
    this.merOrderId = merOrderId;
    submitTime = DateFormatUtils.format(new Date(), "yyyyMMddHHmmss");
    signType = "1";
    this.merAttach = merAttach;
    charset = "1";
    this.tranCode = tranCode;
  }

  public String getCommonSignStr() {
    return VERSION
        + "=["
        + getVersion()
        + "]"
        + TRAN_CODE
        + "=["
        + getTranCode()
        + "]"
        + MER_ID
        + "=["
        + getMerId()
        + "]"
        + MER_ORDER_ID
        + "=["
        + getMerOrderId()
        + "]"
        + SUBMIT_TIME
        + "=["
        + getSubmitTime()
        + "]"
        + MSG_CIPHER_TEXT
        + "=["
        + getMsgCiphertext()
        + "]"
        + SIGN_TYPE
        + "=["
        + getSignType()
        + "]";
  }

  public String getValueByReflect(Object model, String paraName) {
    // 返回值
    String value = "";
    try {
      // 获取属性值
      Field[] fields = model.getClass().getDeclaredFields();
      for (Field field : fields) {
        field.setAccessible(true);
        if (field.getName().equals(paraName)) {
          value = (String) field.get(model);
          break;
        }
      }
    } catch (Exception e) {
      log.error("创建新生支付参数的时候反射错误，", e);
      throw new GlobalRunTimeException(ErrorCode.SYS_ERROR);
    }
    return value;
  }

  public String getJsonStr(Object model, String[] strArr) {
    JSONObject json = new JSONObject(true);
    for (String file : strArr) {
      json.put(file, getValueByReflect(model, file));
    }
    return json.toJSONString();
  }

  public static String getVerifyDataByTranCode(String tranCode, JSONObject jsonObject) {
    StringBuffer sb = new StringBuffer();
    String[] verifyFields = getVerifyArrByTranCode(tranCode);
    for (String key : verifyFields) {
      sb.append(key);
      sb.append("=[");
      String value = jsonObject.getString(key);
      sb.append(value == null ? "" : value);
      sb.append("]");
    }
    return sb.toString();
  }

  public static String getNotifyVerifyDataByTranCode(String tranCode, JSONObject jsonObject) {
    StringBuffer sb = new StringBuffer();
    String[] verifyFields = getNotifyVerifyArrByTranCode(tranCode);
    for (String key : verifyFields) {
      sb.append(key);
      sb.append("=[");
      String value = jsonObject.getString(key);
      sb.append(value == null ? "" : value);
      sb.append("]");
    }
    return sb.toString();
  }

  public static String[] getNotifyVerifyArrByTranCode(String tranCode) {
    return getFieldValueByReflection(tranCode, "notifyVerifyArr");
  }

  private static String[] getVerifyArrByTranCode(String tranCode) {
    return getFieldValueByReflection(tranCode, "verifyArr");
  }

  public static String[] getFieldValueByReflection(String tranCode, String fieldName) {
    tranCode = tranCode.toUpperCase();
    for (Class<? extends BaseTransForm> clazz : SUBTYPE_SET) {
      String className = clazz.getSimpleName();
      if (className.contains(tranCode)) {
        try {
          return (String[]) clazz.getDeclaredField(fieldName).get(null);
        } catch (IllegalAccessException | NoSuchFieldException e) {
          log.error("{}中找不到public的属性名为{}的字段，请定义", className, fieldName);
          throw new GlobalRunTimeException(ErrorCode.SYS_ERROR);
        }
      }
    }
    throw new GlobalRunTimeException(ErrorCode.SYS_ERROR);
  }

  protected static Map<String, Object> generateParam(BaseTransForm transForm, HnaConfig hnaConfig) {
    log.info("-----------请求新生支付，业务参数：{}------------", JSONObject.toJSONString(transForm));
    RSA rsa = SecureUtil.rsa(null, hnaConfig.getHnaPubKey());
    String msgCipherText =
        rsa.encryptBase64(transForm.getEncryptJsonStr(), KeyType.PublicKey)
            .replace("\n", "")
            .replace("\r", "");
    transForm.setMsgCiphertext(msgCipherText);
    Sign sign =
        SecureUtil.sign(SignAlgorithm.SHA1withRSA, hnaConfig.getPriKey(), hnaConfig.getPubKey());
    String signValue =
        Base64.encode(sign.sign(transForm.getCommonSignStr())).replace("\n", "").replace("\r", "");
    transForm.setSignValue(signValue);
    Map<String, Object> map = transForm.getCommonReqSignParams();
    map.put("signValue", signValue);
    map.put("charset", "1");
    return map;
  }
}
